package com.sugar.real.estate.module.business.util.wechat;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sugar.real.estate.framework.common.exception.ServiceException;
import com.sugar.real.estate.module.business.util.wechat.dto.WeChatAccessTokenDTO;
import com.sugar.real.estate.module.business.util.wechat.vo.WeChatOpenIdRespVO;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;

import static com.sugar.real.estate.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.real.estate.module.business.enums.ErrorCodeConstants.*;

/**
 * @author Y.sugar
 * @since 2024/5/10 11:27
 */
@Slf4j
public class WeChatLoginUtil {

    /**
     * 登录凭证校验地址
     */
    private static final String URL = "https://api.weixin.qq.com/sns/jscode2session";

    /**
     * 获取AccessToken地址
     */
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    /**
     * 获取小程序二维码地址
     */
    private static final String QR_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={}";

    /**
     * 获取手机号
     */
    private static final String GET_MOBILE = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={}";

    // 小程序 appId
    private static final String APP_ID = "wx7101ca3df40da7c5";
    // 小程序 appSecret
    private static final String SECRET = "298f4f75ddcb49c792144ebdc2e123f7";

    private static final WeChatAccessTokenDTO ACCESS_TOKEN = new WeChatAccessTokenDTO();

    /**
     * 登录获取用户信息
     *
     * @param code 登录时获取的 code，前端传过来
     * @return 用户信息
     */
    public static WeChatOpenIdRespVO wechatLogin(String code) {
        if (StrUtil.isBlank(code)) {
            return null;
        }

        Map<String, Object> params = new HashMap<>();
        // 小程序 appId
        params.put("appid", APP_ID);
        // 小程序 appSecret
        params.put("secret", SECRET);
        // 添加参数，请求接口
        params.put("js_code", code);
        // 授权类型，此处只需填写 authorization_code
        params.put("grant_type", "authorization_code");
        try {
            String respResStr = HttpUtil.get(URL, params);
            if (StrUtil.isBlank(respResStr)) {
                log.error("请求微信认证接口返回结果为空：{}", respResStr);
                throw exception(WE_CHAT_LOGIN_NOT_RESP);
            }

            // 转为Json对象
            JSONObject respResJson = JSONUtil.parseObj(respResStr);
            // 获取错误码
            String sessionKey = respResJson.getStr("session_key");
            if (StrUtil.isNotBlank(sessionKey)) {
                // 构建对象并赋值
                WeChatOpenIdRespVO loginInfoRespVO = new WeChatOpenIdRespVO();
                loginInfoRespVO.setUnionId(respResJson.getStr("unionid"))
                        .setOpenId(respResJson.getStr("openid"))
                        .setSessionKey(sessionKey);

                return loginInfoRespVO;
            } else {
                log.error("请求微信认证接口失败：{}", respResJson.getStr("errmsg"));
                //throw new ServiceException(respResJson.getInt("errcode"), respResJson.getStr("errmsg"));
                throw exception(WE_CHAT_GET_WECHAT_OPENID_ERROR);
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("微信认证失败：", e);
            throw new ServiceException(500, "微信认证失败");
        }
    }

    public static String getAccessToken() {
        LocalDateTime nowDateTime = LocalDateTime.now();

        String accessToken = ACCESS_TOKEN.getAccessToken();
        if (StrUtil.isNotBlank(accessToken)) {
            Long expiresIn = ACCESS_TOKEN.getExpiresIn();
            LocalDateTime getDateTime = ACCESS_TOKEN.getGetDateTime();
            if (Math.abs(getDateTime.until(nowDateTime, ChronoUnit.SECONDS)) < expiresIn) {
                return accessToken;
            }
        }

        Map<String, Object> params = new HashMap<>();
        // 小程序 appId
        params.put("appid", APP_ID);
        // 小程序 appSecret
        params.put("secret", SECRET);
        // 授权类型，此处只需填写 client_credential
        params.put("grant_type", "client_credential");

        try {
            String respResStr = HttpUtil.get(ACCESS_TOKEN_URL, params);
            if (StrUtil.isBlank(respResStr)) {
                log.error("请求微信认证接口返回结果为空：{}", respResStr);
                throw exception(WE_CHAT_LOGIN_NOT_RESP);
            }

            // 转为Json对象
            JSONObject respResJson = JSONUtil.parseObj(respResStr);
            // 获取错误码
            accessToken = respResJson.getStr("access_token");
            if (StrUtil.isNotBlank(accessToken)) {
                ACCESS_TOKEN.setAccessToken(accessToken).setExpiresIn(respResJson.getLong("expires_in"))
                        .setGetDateTime(nowDateTime);

                return accessToken;
            } else {
                log.error("请求微信认证接口失败：{}", respResJson.getStr("errmsg"));
                //throw new ServiceException(respResJson.getInt("errcode"), respResJson.getStr("errmsg"));
                throw exception(WE_CHAT_GET_WECHAT_OPENID_ERROR);
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("获取微信Token失败：", e);
            throw new ServiceException(500, e.getMessage());
        }
    }

    /**
     * 获取小程序二维码
     *
     * @param invitationCode 当前用户的邀请码
     * @return 小程序二维码
     */
    public static byte[] getLiteQrCodeBytes(String invitationCode) {
        String accessToken = getAccessToken();
        //String accessToken = "83_SX3mjAL2WHDXn7xO2A7jTH0BmG_Lt8635XfftRItJNOq4zjvBWKDoKQF69SFCayXOySktptqGi67gZwqMnUiuXHBKmQo1LINsJ22b2ZoJoKBOUZh3rpbAnd-lIADGAaAGAXAU";
        //System.out.println(JSONUtil.toJsonStr(accessToken));

        try {
            Map<String, Object> params = new HashMap<>();
            // 传递的参数
            params.put("scene", invitationCode);
            // 默认430，二维码的宽度，单位 px
            params.put("width", "280");
            // 是否需要透明底色，true透明，false不透明
            //params.put("is_hyaline", true);

            byte[] respBytes = HttpRequest.post(StrUtil.format(QR_CODE_URL, accessToken))
                    .form("appid", APP_ID, "secret", SECRET)
                    .body(JSONUtil.toJsonStr(params))
                    .execute()
                    .bodyBytes();
            if (respBytes == null || respBytes.length == 0) {
                log.error("请求微信认证接口返回结果为空");
                throw exception(WE_CHAT_LOGIN_NOT_RESP);
            }

            String respResStr = new String(respBytes, StandardCharsets.UTF_8);

            // 判断返回的信息里是否有 "errcode" 字符串
            if (respResStr.contains("errcode")){
                // 转为Json对象
                JSONObject respResJson = JSONUtil.parseObj(respResStr);

                log.error("请求微信认证接口失败：{}", respResStr);
                //throw new ServiceException(respResJson.getInt("errcode"), respResJson.getStr("errmsg"));
                throw exception(WE_CHAT_GET_WECHAT_OPENID_ERROR);
            }else {
                return respBytes;
            }
        } catch (ServiceException e) {
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("获取小程序二维码失败：", e);
            throw new ServiceException(500, e.getMessage());
        }
    }

    /**
     * 获取用户手机号
     *
     * @param code 手机号获取凭证
     * @return 用户手机号
     */
    public static String getUserMobile(String code) {
        if (StrUtil.isBlank(code)){
            throw exception(WE_CHAT_MOBILE_GET_AUTH_IS_NULL);
        }
        String accessToken = getAccessToken();

        try {
            Map<String, Object> params = new HashMap<>();
            // 传递的参数
            params.put("code", code);

            byte[] respBytes = HttpRequest.post(StrUtil.format(GET_MOBILE, accessToken))
                    .form("appid", APP_ID, "secret", SECRET)
                    .body(JSONUtil.toJsonStr(params))
                    .execute()
                    .bodyBytes();
            if (respBytes == null || respBytes.length == 0) {
                log.error("请求微信认证接口返回结果为空");
                throw exception(WE_CHAT_LOGIN_NOT_RESP);
            }

            String respResStr = new String(respBytes, StandardCharsets.UTF_8);
            // 转为Json对象
            JSONObject respResJson = JSONUtil.parseObj(respResStr);

            // 判断返回的信息里是否有 "errcode" 字符串
            if (respResJson.getInt("errcode") == 0){
                return respResJson.getJSONObject("phone_info").getStr("purePhoneNumber");
            }else {
                log.error("请求微信认证接口失败：{}", respResStr);
                //throw new ServiceException(respResJson.getInt("errcode"), respResJson.getStr("errmsg"));
                throw exception(WE_CHAT_GET_WECHAT_OPENID_ERROR);
            }
        } catch (ServiceException e) {
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("获取用户手机号失败：", e);
            throw new ServiceException(500, e.getMessage());
        }
    }

}
